#include "server.h"

int ExitPipe[2];
MYSQL* mySql;

//通知子进程退出
void ExitFunc(int SigNum){
    printf("signal %d is coming",SigNum);
    char ch=1;
    write(ExitPipe[1],&ch,1);
}

//传入参数ip,port,threadnum
int main(int argc,char *argv[]){
    //初始化数据库并与数据库服务器建立连接
    mySql = mysql_init(NULL);
    mysql_real_connect(mySql, "localhost", "root", "lkl990606", "netdisk", 0, NULL, 0);
    //检查参数，并进行参数类型转化
    ARGS_CHECK(argc,4);
    int threadNum=atoi(argv[3]);
    char *ip=argv[1];
    int port=atoi(argv[2]);
    //注册信号，并建立匿名管道用于通知子进程退出
    signal(SIGUSR1,ExitFunc);
    pipe(ExitPipe);
    //创建子线程
    pid_t pid=fork();
    //父进程等待子进程结束，然后关闭数据库连接并退出
    if(pid>0){
        close(ExitPipe[0]);
        wait(NULL);
        mysql_close(mySql);
        exit(0);
    }
    //子进程创建线程库
    close(ExitPipe[1]);
    thread_pool_t threadPool;
    threadpoolInit(&threadPool,threadNum);
    threadpoolStart(&threadPool);
    //创建服务器端listen套接字
    int listenfd=tcpServerInit(ip,port);
    //创建epoll对象和事件链表，并将匿名管道和listen加入监听事件
    int epfd=epollCreate();
    epollAddReadEvent(epfd,listenfd);
    epollAddReadEvent(epfd,ExitPipe[0]);
    struct epoll_event *pEvtList=(struct epoll_event *)calloc(MAXCONNS,sizeof(struct epoll_event));
    //开始监听
    while(1){
        int nReady = 0;
        do{
            nReady=epoll_wait(epfd,pEvtList,MAXCONNS,5000);
        }while(nReady==-1&&errno==EINTR);

        if(nReady==0){
            //五秒内没有用户接入则打印epoll timeout.
            printf("epoll timeout.\n");
            continue;
        }else if(nReady==-1){
            //返回值为-1说明出现错误，且错误类型不为RINTR，直接退出while循环
            perror("epoll_wait");
            break;
        }else{
            //对准备就绪的文件描述符进行处理
            for(int i=0;i<nReady;i++){
                int fd=pEvtList[i].data.fd;
                if(fd==listenfd){
                    //新客户加入
                    int peerfd=accept(listenfd,NULL,NULL);
                    if(peerfd<0){
                        perror("accept");
                    }
                    printf("accept a new connect.peerfd:%d\n",peerfd);
                    taskEnqueue(&threadPool.queue,peerfd);
                }else if(fd==ExitPipe[0]){
                    //收到退出通知，子进程逐步退出
                    char exitFlag;
                    read(ExitPipe[0],&exitFlag,1);
                    printf("parent process ready to exit.\n");
                    queueWakeup(&threadPool.queue);
                    for(int j=0;j<threadNum;j++){
                        pthread_join(threadPool.threads[j],NULL);
                    }
                    printf("parent process pool exit.\n");
                    threadpoolDestroy(&threadPool);
                    exit(0);
                }
            }
        }
    }
    //释放资源和关闭文件描述符
    free(pEvtList);
    close(listenfd);
    close(epfd);
    return 0;
}

